package org.processmining.plugins.complianceframework.visualization;

import java.awt.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import org.processmining.plugins.complianceframework.ComplianceDashboard;

public class DashboardTableModel extends DefaultTableModel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 4388593443760485012L;

	public DashboardTableModel() {
		super();
	}

	public DashboardTableModel(Object[][] data, Object[] columnNames) {
		super(data, columnNames);
	}

	public DashboardTableModel(ComplianceDashboard dashboard,
			String visualizationMode, boolean showCaseFrequency) {
		// Object[] columns = setupColumns(dashboard, visualizationMode);
		// Object[][] rows = setupRows(dashboard, visualizationMode,
		// showCaseFrequency);
		super(setupRows(dashboard, visualizationMode, showCaseFrequency),
				setupColumns(dashboard, visualizationMode));
	}

	@Override
	public boolean isCellEditable(int row, int column) {
		return false;
	}

	private static Object[] setupColumns(ComplianceDashboard dashboard,
			String visualizationMode) {
		Object[] result = new Object[dashboard.getCombinations().size() * 2 + 6];
		result[0] = visualizationMode;
		result[1] = "Invisible moves";
		result[2] = "Synchronous moves";
		result[dashboard.getCombinations().size() * 2 + 3] = "Log-only moves";
		result[dashboard.getCombinations().size() * 2 + 4] = "Model-only moves";
		result[dashboard.getCombinations().size() * 2 + 5] = "Total moves";
		for (int i = 0; i < dashboard.getCombinations().size(); i++) {
			if (i == (dashboard.getCombinations().size() - 1)
					&& dashboard.getCombinations().get(i).size() > 2) {
				result[i + 3] = "All aspects correct";
				result[dashboard.getCombinations().size() + i + 3] = "All aspects inccorrect";
			} else {
				String fieldName = "";
				for (int j = 0; j < dashboard.getCombinations().get(i).size(); j++) {
					fieldName += dashboard.getCombinations().get(i).get(j);
					if (j < dashboard.getCombinations().get(i).size() - 1)
						fieldName += ", ";
				}
				result[i + 3] = "Correct " + fieldName;
				result[dashboard.getCombinations().size() + i + 3] = "Incorrect "
						+ fieldName;
			}
		}

		return result;
	}

	private static Object[][] setupRows(ComplianceDashboard dashboard,
			String visualizationMode, boolean showCaseFrequency) {
		Object[][] result;
		if (visualizationMode.equals("Activity")) {
			result = new Object[dashboard.getActivityMovesMap().size()][];
			int i = 0;
			Set<Entry<String, int[]>> entrySet;
			if (!showCaseFrequency)
				entrySet = dashboard
						.getActivityMovesMap().entrySet();
			else
				entrySet = dashboard
						.getActivityCaseFreqMap().entrySet();
			for (Entry<String, int[]> activityEntry : entrySet) {
				result[i] = new Object[activityEntry.getValue().length + 2];
				result[i][0] = activityEntry.getKey();
				result[i][result[i].length - 1] = activityEntry.getValue()[0]
						+ activityEntry.getValue()[1]
						+ activityEntry.getValue()[activityEntry.getValue().length - 2];
				for (int j = 1; j < result[i].length - 1; j++) {
					result[i][j] = activityEntry.getValue()[j - 1];
				}
				i++;
			}
		} else {
			result = new Object[dashboard.getAttributeMovesMap()
					.get(visualizationMode).size()][];
			int i = 0;
			Set<Entry<String, int[]>> entrySet;
			if (!showCaseFrequency)
				entrySet = dashboard
						.getAttributeMovesMap().get(visualizationMode).entrySet();
			else
				entrySet = dashboard
				.getAttributeCaseFreqMap().get(visualizationMode).entrySet();
			for (Entry<String, int[]> attributeEntry : entrySet) {
				result[i] = new Object[attributeEntry.getValue().length + 2];
				result[i][0] = dashboard.getIntervalByIDOrValue(visualizationMode,
						attributeEntry.getKey());
				result[i][result[i].length - 1] = attributeEntry.getValue()[0]
						+ attributeEntry.getValue()[1]
						+ attributeEntry.getValue()[attributeEntry.getValue().length - 2];
				for (int j = 1; j < result[i].length - 1; j++) {
					result[i][j] = attributeEntry.getValue()[j - 1];
				}

				i++;
			}
		}

		return result;
	}
}

class DashboardTableCellRenderer extends DefaultTableCellRenderer {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8991975221529546601L;
	private Map<TableColumn, java.awt.Color> columnColorMap;
	private static final int maxColorIntensity = 150;

	public DashboardTableCellRenderer() {
		super();
	}

	public DashboardTableCellRenderer(JTable table,
			ComplianceDashboard dashboard) {
		super();
		init(table, dashboard);
	}

	public void init(JTable table, ComplianceDashboard dashboard) {
		TableColumnModel tcm = table.getColumnModel();
		columnColorMap = new HashMap<TableColumn, java.awt.Color>();
		// column with row names
		columnColorMap.put(tcm.getColumn(0), new java.awt.Color(75, 75, 75));
		columnColorMap.put(tcm.getColumn(1), new java.awt.Color(80, 80, 80));
		int maxEls = dashboard.getCombinations()
				.get(dashboard.getCombinations().size() - 1).size();
		float intensity = (0.5f / (float) maxEls) * maxColorIntensity;
		// sync moves
		columnColorMap.put(tcm.getColumn(2),
				new java.awt.Color(0, Math.round(intensity), 0));
		// sync moves with correct & incorrect params
		for (int i = 0; i < dashboard.getCombinations().size(); i++) {
			intensity = ((float) dashboard.getCombinations().get(i).size() / (float) maxEls)
					* maxColorIntensity;
			columnColorMap.put(tcm.getColumn(i + 3),
					new java.awt.Color(0, Math.round(intensity), 0));
			columnColorMap.put(
					tcm.getColumn(dashboard.getCombinations().size() + i + 3),
					new java.awt.Color(Math.round(intensity), 0, 0));
		}
		// async moves
		columnColorMap.put(tcm.getColumn(table.getColumnCount() - 3),
				new java.awt.Color(maxColorIntensity, 0, 0));
		columnColorMap.put(tcm.getColumn(table.getColumnCount() - 2),
				new java.awt.Color(maxColorIntensity, 0, 0));
		columnColorMap.put(tcm.getColumn(table.getColumnCount() - 1),
				new java.awt.Color(75, 75, 75));
	}

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		Component c = super.getTableCellRendererComponent(table, value,
				isSelected, hasFocus, row, column);
		// TableColumn currentColumn = table.getColumn(
		// table.getColumnName(column));
		TableColumn currentColumn = table.getColumnModel().getColumn(column);
		
		if (columnColorMap.containsKey(currentColumn))
			c.setBackground(columnColorMap.get(currentColumn));
		else {
			if (column == 0) {
				c.setBackground(new java.awt.Color(75, 75, 75));
			} else if (column >= table.getColumnCount() - 3) {
				c.setBackground(new java.awt.Color(150, 0, 0));
			} else {
				float intensity = 0.0f;
				int middle = (table.getColumnCount() - 5) / 2;
				try {
					if (column > middle + 1) {
						intensity = (float) (column - (middle + 1))
								/ ((float) middle);
						c.setBackground(new java.awt.Color(Math
								.round(150.0 * intensity), 0, 0));
					} else {
						intensity = (float) (column - 1) / (float) middle;
						c.setBackground(new java.awt.Color(0, Math
								.round(150.0f * intensity), 0));
					}
				} catch (Exception ex) {
					int a = 5;
					int b = a + 5;
				}
			}
			columnColorMap.put(currentColumn, c.getBackground());
		}

		return c;
	}
}